﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace Neotic.DataAccess.Sql.Operations
{
    internal static class OperatorExpressionManager
    {
                //ParameterExpression param = (ParameterExpression)predicate.Parameters[0];
                //BinaryExpression operation = (BinaryExpression)predicate.Body;
                
                //ParameterExpression left = (ParameterExpression)operation.Left;
                //ConstantExpression right = (ConstantExpression)operation.Right;

        
        private static readonly Dictionary<ExpressionType, List<ISqlCondition>> _operators = new Dictionary<ExpressionType, List<ISqlCondition>>();

        /// <summary>
        /// initialise les operateurs disponible pour convertir les expressions C# et SQL
        /// </summary>
        private static void Initialize()
        {
            lock (_operators)
            {
                if (_operators.Count == 0)
                {
                    foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        foreach (Type t in a.GetTypes())
                        {
                            foreach (Type i in t.GetInterfaces())
                            {
                                if (i == typeof(ISqlCondition))
                                {
                                    try
                                    {
                                        ISqlCondition cdt = (ISqlCondition)t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null).Invoke(null);
                                        if (cdt != null && cdt.MyExpressionType != null)
                                        {
                                            List<ISqlCondition> l = null;
                                            ExpressionType expType = (ExpressionType)cdt.MyExpressionType;
                                            if (!_operators.TryGetValue(expType, out l))
                                            {
                                                l = new List<ISqlCondition>();
                                            }
                                            l.Add(cdt);
                                            _operators[expType] = l;
                                        }
                                    }
                                    catch {}
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Trouve l'opérator pour convertir le prédicate (expression C#) en ISqlCondition
        /// </summary>
        /// <param name="predicate">expression C#</param>
        /// <returns>ISqlCondition correspondant au prédicate, Null si aucun opérateur ne correspond</returns>
        public static ISqlCondition FindOp(Expression<Func<ISqlCondition, object>> predicate)
        {
            if (_operators.Count == 0)
                Initialize();

            List<ISqlCondition> ops;
            
            if (_operators.TryGetValue(predicate.NodeType, out ops))
            {
                foreach (ISqlCondition op in ops)
                {
                    ISqlCondition res =op.ParseExpression(predicate);

                    if (res != null)
                        return res;
                }            
            }

            return null;
        }
    }
}
